"""
API场景组合测试工具 - 认证服务
"""
import json
import requests
from datetime import datetime, timedelta
from app import db
from app.models.auth_cache import AuthCache
from app.models.environment import Environment
from app.utils.variable_processor import process_variables
from playwright.sync_api import sync_playwright

class AuthService:
    """认证服务，处理API认证和登录"""
    
    def authenticate(self, environment_id, auth_config):
        """执行认证流程"""
        # 获取认证类型
        auth_type = auth_config.get('type', 'none')
        
        if auth_type == 'none':
            return {}
        elif auth_type == 'basic':
            return self._basic_auth(auth_config)
        elif auth_type == 'bearer':
            return self._bearer_auth(auth_config)
        elif auth_type == 'api':
            return self._api_auth(environment_id, auth_config)
        elif auth_type == 'web':
            return self._web_auth(environment_id, auth_config)
        else:
            raise ValueError(f'不支持的认证类型: {auth_type}')
    
    def _basic_auth(self, auth_config):
        """基本认证"""
        username = auth_config.get('username', '')
        password = auth_config.get('password', '')
        
        import base64
        auth_string = base64.b64encode(f"{username}:{password}".encode()).decode()
        
        return {
            'headers': {
                'Authorization': f'Basic {auth_string}'
            }
        }
    
    def _bearer_auth(self, auth_config):
        """Bearer令牌认证"""
        token = auth_config.get('token', '')
        
        return {
            'headers': {
                'Authorization': f'Bearer {token}'
            }
        }
    
    def _api_auth(self, environment_id, auth_config):
        """API认证"""
        # 获取环境信息
        environment = Environment.query.get(environment_id)
        env_config = json.loads(environment.config) if environment.config else {}
        
        # 获取认证API配置
        auth_api = auth_config.get('api', {})
        url = auth_api.get('url', '')
        method = auth_api.get('method', 'POST')
        headers = auth_api.get('headers', {})
        body = auth_api.get('body', {})
        
        # 处理URL
        base_url = environment.base_url or env_config.get('base_url', '')
        if not url.startswith(('http://', 'https://')):
            url = f"{base_url.rstrip('/')}/{url.lstrip('/')}"
        
        # 发送认证请求
        try:
            response = requests.request(
                method=method,
                url=url,
                headers=headers,
                json=body,
                timeout=30
            )
            
            # 检查响应状态
            if response.status_code != 200:
                raise Exception(f'认证请求失败: {response.status_code} {response.text}')
            
            # 解析响应
            try:
                response_data = response.json()
            except:
                response_data = {'text': response.text}
            
            # 提取令牌
            token_path = auth_api.get('token_path', '')
            token = self._extract_value(response_data, token_path)
            
            if not token:
                raise Exception('无法从响应中提取令牌')
            
            # 提取过期时间
            expires_in = None
            expires_path = auth_api.get('expires_path', '')
            if expires_path:
                expires_in_value = self._extract_value(response_data, expires_path)
                if expires_in_value:
                    try:
                        expires_in = int(expires_in_value)
                    except:
                        pass
            
            # 创建认证缓存
            auth_data = {
                'headers': {
                    'Authorization': f'Bearer {token}'
                },
                'token': token,
                'response': response_data
            }
            
            self._save_auth_cache(environment_id, auth_data, expires_in)
            
            return auth_data
        except Exception as e:
            raise Exception(f'API认证失败: {str(e)}')
    
    def _web_auth(self, environment_id, auth_config):
        """Web页面认证（使用Playwright）"""
        # 获取环境信息
        environment = Environment.query.get(environment_id)
        
        # 获取认证配置
        url = auth_config.get('url', '')
        username_selector = auth_config.get('username_selector', '')
        password_selector = auth_config.get('password_selector', '')
        submit_selector = auth_config.get('submit_selector', '')
        username = auth_config.get('username', '')
        password = auth_config.get('password', '')
        
        # 等待选择器
        wait_selector = auth_config.get('wait_selector', '')
        
        # 提取令牌的脚本
        extract_script = auth_config.get('extract_script', '')
        
        try:
            with sync_playwright() as p:
                # 启动浏览器
                browser = p.chromium.launch(headless=True)
                context = browser.new_context()
                page = context.new_page()
                
                # 导航到登录页面
                page.goto(url)
                
                # 填写登录表单
                if username_selector and username:
                    page.fill(username_selector, username)
                
                if password_selector and password:
                    page.fill(password_selector, password)
                
                # 提交表单
                if submit_selector:
                    page.click(submit_selector)
                
                # 等待页面加载完成
                if wait_selector:
                    page.wait_for_selector(wait_selector)
                else:
                    page.wait_for_load_state('networkidle')
                
                # 提取令牌
                token = None
                if extract_script:
                    token = page.evaluate(extract_script)
                
                # 提取cookies
                cookies = context.cookies()
                
                # 关闭浏览器
                browser.close()
                
                # 处理认证数据
                auth_data = {
                    'headers': {},
                    'cookies': cookies
                }
                
                if token:
                    auth_data['headers']['Authorization'] = f'Bearer {token}'
                    auth_data['token'] = token
                
                # 创建认证缓存
                self._save_auth_cache(environment_id, auth_data)
                
                return auth_data
        except Exception as e:
            raise Exception(f'Web认证失败: {str(e)}')
    
    def _extract_value(self, data, path):
        """从数据中提取值"""
        if not path:
            return None
        
        parts = path.split('.')
        current = data
        
        for part in parts:
            if isinstance(current, dict) and part in current:
                current = current[part]
            else:
                return None
        
        return current
    
    def _save_auth_cache(self, environment_id, auth_data, expires_in=None):
        """保存认证缓存"""
        # 将之前的缓存标记为无效
        AuthCache.query.filter_by(environment_id=environment_id).update({'is_valid': False})
        
        # 创建新的缓存
        auth_cache = AuthCache(
            environment_id=environment_id,
            auth_data=json.dumps(auth_data),
            is_valid=True
        )
        
        if expires_in:
            auth_cache.expires_at = datetime.now() + timedelta(seconds=expires_in)
        
        db.session.add(auth_cache)
        db.session.commit()